using System.Diagnostics.CodeAnalysis;

namespace UnitTesting.Fixturing
{
	class TargetParams<T>
	{
		internal IConstructorSpecifier<T> ConstructorSpecifier { get; set; }

		internal IArgumentSpecifier ArgumentSpecifier { get; set; }

		internal TestObjectCreator<T> TestObjectCreator { get; set; }

		[SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
		internal TargetParams(IValueProvider valueProvider, IFreezable freezable, object fixtureOptions)
		{
			var reflectionValueProvider = CreateReflectionValueProvider(valueProvider, freezable, fixtureOptions);
			ConstructorSpecifier = reflectionValueProvider;
			ArgumentSpecifier = reflectionValueProvider;
			SetTargetObjectCreator(reflectionValueProvider, freezable);
		}

		internal virtual ReflectionValueProviderFor<T> CreateReflectionValueProvider(
			IValueProvider valueProvider, IFreezable freezable, object fixtureOptions)
		{
			return new ReflectionValueProviderFor<T>(valueProvider, freezable, fixtureOptions);
		}

		internal TargetParams()
		{
		}

		void SetTargetObjectCreator(ReflectionValueProviderFor<T> reflectionValueProvider, IFreezable freezable)
		{
			var compositeValueProvider = new StaticCompositeValueProvider(
				(IValueProvider) freezable, reflectionValueProvider);

			var guardNotResovledValue = CreateGuardNotResovledValue(compositeValueProvider);

			TestObjectCreator = CreateTestObjectCreator(guardNotResovledValue, freezable);
		}

		internal virtual IValueProvider CreateGuardNotResovledValue(IValueProvider valueProvider)
		{
			return new GuardNotResovledValue(valueProvider);
		}

		internal virtual TestObjectCreator<T> CreateTestObjectCreator(IValueProvider valueProvider, IFreezable freezable)
		{
			return new TestObjectCreator<T>(valueProvider, freezable);
		}
	}
}